Skip to content

Merge release-1.11 into develop - #10084

Open
infrahub-github-bot-app[bot] wants to merge 80 commits into
developfrom
release-1.11
Open

Merge release-1.11 into develop#10084
infrahub-github-bot-app[bot] wants to merge 80 commits into
developfrom
release-1.11

Conversation

@infrahub-github-bot-app

@infrahub-github-bot-app infrahub-github-bot-app Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Merging release-1.11 into develop after merging pull request #10077.


Summary by cubic

Merges release-1.11 into develop. Adds Phase 1 anonymous telemetry (24h activity, adoption metrics), the @urql GraphQL transport, the new IPAddress kind, stricter schema‑load reporting, faster id‑only relationship reads, and validator/uniqueness wiring; also fixes recompute gaps, form filters, and git sync on merged branches.

  • Refactors

    • Replaced Apollo with an imperative graphqlClient using @urql/core; removed <ApolloProvider>. Kept TanStack Query; no GraphQL hooks/cache. Auth via @urql/exchange-auth. Preserved request‑priority and uploads. Removed @apollo/client, apollo-upload-client, @types/apollo-upload-client; added @urql/core, @urql/exchange-auth. Regenerated GraphQL types. (INFP‑563)
    • Validator plumbing: MergeConstraintValidator now receives an injected determiner and a constraint‑info merger. The determiner/scoper/deduplicator accept schema_branch at call time (merge/rebase/proposed‑change, builders).
    • GraphQL relationship reads: id‑only single‑relationship fields now return the preloaded peer stub and skip hydration; the peer’s concrete kind is carried so generic peers also skip hydration.
    • Attribute kinds: added IPAddress (bare IP without mask). _normalize_value is a classmethod; changing a kind is rejected unless stored values are already canonical for the new kind. GraphQL exposes IPAddressType; SDK/types updated.
    • Schema load: validates through the write contract; reports dropped read‑only fields as warnings, rejects unknown fields and misplaced attribute parameters, and returns warnings even when the submitted schema is unchanged. Repository imports surface the same warnings and fail on unknown fields.
    • Telemetry (INFP‑589): added adoption and activity signals. New fields: accounts.active, accounts.groups, branches.active, database.node_count.corenode, database.node_count.user, and a 24h windowed activity_24h summary (logins/unique_logins, checks started/passed/failed, artifacts created/updated, branches created/merged/deleted, webhook deliveries succeeded/failed). Window is the previous full UTC day; each metric degrades independently to null on failure. Counts reuse branch‑aware paths and a single pass over kinds where possible.
    • Fingerprints: Jinja2 transforms with a complete dependency closure now omit the commit id and produce stable fingerprints without a watch; Python transforms/generators still require a watch. Unrelated commits no longer churn complete Jinja2 fingerprints.
  • Bug Fixes

    • Uniqueness checks: node‑scoped validations reach participating fields in mixed diffs and deduplicate across inheritance when broadened by schema changes; rebase paths pass the candidate schema_branch.
    • Coalesced recompute: relationship changes and deletions refresh readers’ computed attributes, display labels, and HFIDs, including cross‑relationship HFIDs; tolerant of profile/template kinds and kinds missing from the branch.
    • Jinja2 computed attributes: macros reading a number‑pool value defer until allocation; attributes depending on a deferred macro also skip until ready. Repository imports no longer always mark Jinja2 transforms as updated; template_path comparison normalizes Path vs string.
    • Frontend forms: relationship selectors honor common_parent; selections clear on parent change and inline “Add new” pre‑fills the parent.
    • Git sync: branches in a terminal (merged/deleting) state are skipped to avoid aborting repository synchronization.

Written for commit 7d3fca3. Summary will update on new commits.

Review in cubic

saltas888 and others added 30 commits July 10, 2026 17:17
Add additive, backwards-compatible telemetry payload metrics spec:
accounts.active/groups, branches.active, database.node_count.corenode,
and the activity_24h object (logins, unique_logins, webhook success/failure).
Producer-only; user_node_count (IFC-2825) and Phase 2 items out of scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add plan.md, research.md, data-model.md, contracts/telemetry-payload.md,
quickstart.md. Grounded in existing telemetry module: NodeManager.count for
branch/temporal-correct counts, new windowed Prefect path for activity_24h,
per-metric graceful-degradation (null on failure, 0 on empty), payload_format
bump. Constitution check passes (no new entities/deps).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verdict PROCEED. Applied two Must-Address fixes: (1) firm up no-mock test
strategy (degradation helper unit-tested directly, freezegun for 24h windowing);
(2) extend GR-001/SC-004 + contract to require consumer tolerance of null values,
including corenode-in-node_count. Documented webhook non-terminal handling and
corenode count cost.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 tasks across Setup, Foundational (models, payload_format bump, degradation
helper), US1 activity_24h enabler (MVP), US2 accounts/branches, US3 corenode,
US4 full-payload resilience, and Polish (incl. GR-001 governance gate). TDD
test-first per Constitution IV; no-mock + freezegun guardrails noted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Source: inline handoff PRD (no URLs). Verdict ALIGNED, 0 remediation passes.
All in-scope FRs and SCs faithfully carried; SC-004 + null-tolerance are
justified clarifications, not scope creep. Out-of-scope items preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ed node metrics

Reviewer feedback on prep output:
- Anchor activity_24h to the previous full UTC calendar day (not gather-time
  now), so daily snapshots tile with no overlap/gap despite the jittered cron
  minute and execution drift (sharpens SC-002).
- Pin node-metric definitions at the namespace level: corenode = Core+Builtin+
  user namespaces (always includes Core mgmt), user = customer-facing subset
  excluding Core; user ⊆ corenode ⊆ total, so they can never become synonyms
  (sharpens FR-009). Verified via get_labels().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
User-directed scope expansion after a grilling pass. validator.started/passed/
failed -> activity_24h.checks_*, artifact.created/updated -> activity_24h.
artifacts_*. Verified via get_all_events() that both event families already
flow and are counted today, so they reuse the US1 windowed path unchanged
(~1 event name + a parametrized test each) and serve the stated depth-of-
adoption goal.

Held in Phase 2 despite existing events (value needs correlation, not raw
counts): PR governance (proposed_change.*), branch lifetime (branch.*), node
churn (node.*). Recorded as sanctioned expansion in alignment-check.md.

Adds FR-012/FR-013, US5 phase (T022-T023), renumbers US4->Phase7/Polish->Phase8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conceded a misclassification: branch *lifecycle counts* (created/merged/deleted)
need no correlation and are a first-class adoption signal for the branch-based
workflow, so they belong with checks/artifacts by the same already-flowing-event
rule. Only branch *lifetime* (duration) needs correlation and stays Phase 2.

Adds FR-014 + activity_24h.branches_created/merged/deleted (verified present via
get_all_events). Held on merit: node churn (machine-dominated/noisy), branch
rebased/migrated (low-signal), PR merged-without-review + branch lifetime (need
correlation). ~16 new payload fields total.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…es-only asymmetry

Keep checks_started as the rate denominator (pass/failure/incomplete rates);
document that the three checks_* fields are non-additive. Record that webhooks
are intentionally outcomes-only this phase (no attempted denominator), an
additive-later choice, so the checks/webhooks asymmetry is deliberate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ntities entry

Reframe FR-009 definitions operationally (by how each is computed): total = raw
vertices; corenode = CoreNode-generic via branch-safe NodeManager.count (every
schema-managed node whose namespace is not Schema/Internal, incl. CoreAccount);
user = future/blocked customer-facing subset with an open Builtin boundary that
must not be assumed. Add a node-count-metrics entry to Key Entities so the entity
list matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a Towncrier 'added' fragment describing the new additive telemetry
payload fields (accounts, branches.active, node_count.corenode, the
activity_24h object) and the payload_format bump.

Create empty, collectible pytest skeletons for the upcoming degradation
helper unit test and the gather-flow component test, mirroring the
telemetry source layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…elper

Bump TELEMETRY_VERSION to 20260628 (advancing DEFAULT_PAYLOAD_FORMAT).
Add additive payload models: TelemetryAccountData, TelemetryActivity24hData,
extend TelemetryBranchData with active, widen TelemetryDatabaseData.node_count
values to allow null on a per-key basis, and add accounts/activity_24h to
TelemetryData as always-present objects with per-field nullability.

Add safe_metric, an async per-metric graceful-degradation helper that returns a
coroutine's result or null on failure (logged), so one failing source nulls only
its own field instead of dropping the whole payload. Covered by a no-mock unit
test using plain coroutines as doubles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a deterministic 24h window (previous full UTC calendar day, anchored to
midnight) and a new windowed Prefect event path feeding activity_24h:

- window.py: floor_to_midnight_utc + get_activity_window returning
  [window_start, window_end) so consecutive daily runs tile exactly.
- task_manager.py: count_windowed_event (/events/count-by/event with an
  occurred window), count_windowed_unique_resources (/events/count-by/resource
  bucket count = unique logins), and count_webhook_runs (webhook-process
  flow runs split COMPLETED vs FAILED/CRASHED; non-terminal counted in
  neither). gather_activity_24h assembles logins/unique_logins/webhook
  success+failure via per-field degradation; check/artifact/branch fields
  stay null for a later chunk.
- tasks.py: wire activity_24h into gather_anonymous_telemetry_data via the
  Prefect client. The existing unwindowed gather_prefect_events is untouched.
- Move safe_metric to utils.py (re-exported from tasks.py) to avoid an import
  cycle now that task_manager.py needs per-field degradation.

Component tests seed login events with explicit occurred timestamps and
webhook flow runs around the window boundary, asserting in-window-only counts,
distinct-account collapsing, terminal-state splitting, and that the existing
event tally is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `gather_account_information` returning active-account and account-group
counts via the branch/temporal-correct count path on the default branch, each
isolated through the per-metric degradation helper. Add `count_active_branches`
counting open non-system registry branches (excluding the default and global
branches). Wire both into the anonymous telemetry payload, replacing the
accounts placeholder and adding `branches.active` while leaving `branches.total`
unchanged. Cover both with component tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…etrics

Set node_count["corenode"] via NodeManager.count on the CoreNode generic
(InfrahubKind.NODE) on the default branch, so the managed-node count is
branch- and temporal-correct rather than a raw label tally. The computation
is isolated in its own try/except: a failure nulls only the corenode key
while the raw total and per-graph-label counts stay intact and the payload
still ships.

Document the three node metrics at the namespace level (user subset of
corenode subset of total) so corenode and a future user metric can never
become synonyms. Add a component test that seeds managed nodes and asserts
corenode matches an independently-computed count exactly while total is
preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… counts

Populate the eight check/artifact/branch activity_24h fields from windowed
Prefect event counts over the previous full UTC calendar day, each isolated
through the degradation helper so one failing source nulls only its own field.
gather_prefect_events is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an optional injection seam to gather_anonymous_telemetry_data so the
orchestrator's per-source isolation can be exercised with a real failing
coroutine instead of a mock. Each orchestrator-level new source (accounts,
activity_24h, active-branch count) is now gathered through the degradation
helper, so a whole-source failure degrades only its own field(s) to null
while the rest of the payload is still built and stored.

Component tests cover: every new field present on a healthy gather,
genuine-empty windows reporting 0 (not null), and one failing source
nulling only its own field(s) with the snapshot still persisted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review finding: count_webhook_runs used len(read_flow_runs(...)), which caps at
the Prefect server default page size (200) and would silently undercount a busy
deployment's daily webhook volume. Switch to client.count_flow_runs for an exact,
unpaginated total. Webhook component tests still green; full telemetry suite 62 passed.

Tick T027 (suite green), T028 (lint clean), T029 (local collection simulation
verified payload_format + all new fields). T030 (governance gate) remains open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Chunk ledger, local-pass evidence (62 passed), review findings (webhook count
fix applied inline; unique_logins bucket-cap + TIMEDOUT doc drift deferred),
autonomous decisions, next steps. T030 governance gate remains the one open
external item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…trics

Add database.node_count["user"]: the count of concrete nodes living in
user-defined (non-restricted) namespaces, counted branch/temporal-correctly
on the default branch. This is the customer-facing subset — it excludes the
Core management namespace, pipeline validators/checks, and by default Builtin
kinds. Generics, profiles, templates, and group-generic kinds are skipped so
that user stays a strict subset of corenode (groups do not carry the CoreNode
label), preserving the user ⊆ corenode ⊆ total nesting invariant.

The block is isolated in its own try/except mirroring corenode, so a failure
nulls only node_count["user"] while total and the per-graph-label keys remain
populated and the payload still ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
user-node count moved from parked (IFC-2825) to in-scope now the namespace
boundary is resolved: count user-defined-namespace kinds via the
RESTRICTED_NAMESPACES negative filter (excludes Core incl. pipeline
validators/checks, and Builtin). Reinstate FR-004, rewrite FR-009 with the
corenode pipeline-inflation caveat, update data-model/contract/research/tasks/
changelog. Three node metrics nest user ⊆ corenode ⊆ total.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prefect's EventOccurredFilter is inclusive on both since and until, and the
flow-run start_time.before_ filter is 'at or before' — so passing
until=window_end counted an event stamped exactly at midnight in two
consecutive daily windows. Found via a live multi-day tiling simulation
(4 windows over 12 seeded events summed to 14). Pull the upper bound back
one microsecond on both windowed paths so the effective interval is the
documented [start, end); tiling now sums exactly.

Regression: seeded_logins now places events at exactly window_start
(counted) and exactly window_end (excluded, belongs to the next day).
Suite: 63 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Route the per-metric fallbacks in the database gather through the single
safe_metric boundary instead of duplicating broad try/except blocks, so a
failing source nulls only its own field. Trim comments and docstrings across
the telemetry collection code to the WHY.

Add a concept doc for how telemetry works (categories, the three temporal
models, windowing vs retention, graceful degradation) and a manual test plan
plus an ad-hoc window probe under the spec. Add a unit test documenting the
validator-event emission asymmetry that makes checks_started exceed the
terminal counts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Event.occurred is typed as Prefect's DateTime subclass, not stdlib datetime;
mypy rejected the plain datetime built for window-boundary test fixtures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the None-sentinel-plus-or-fallback pattern in
gather_anonymous_telemetry_data with direct callable defaults — the
production gatherers are already plain functions defined above their use
site, so the optional-with-internal-default shape this project's DI
guideline flags was unnecessary here. Drop the redundant __all__ re-export
(safe_metric is already used directly in this module).

Document activity_24h field semantics in the telemetry knowledge doc,
clarifying that logins/unique_logins count interactive sign-ins (password,
OIDC, OAuth2) only — per-request API-key/token auth never emits a login
event.

Revert the CLAUDE.md Spec Kit plan-pointer stamp: the same pattern was
already reverted once on another feature branch (37d0417) since it
hard-codes one feature's plan path into a file shared across all branches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…entation

window_probe.py typed its Prefect client parameters as `object` instead of
PrefectClient, which the CI ty-check gate rejects when passed to
count_webhook_runs.fn/count_windowed_event.fn.

Also reconcile spec docs raised in review:
- spec.md: document that configured database-core reporting was pulled into
  Phase 1 per the Jira scope-change call, then deferred back out during
  implementation (the candidate setting is REST-only and would only
  duplicate processor_available) — the Out of Scope section previously gave
  no reason, reading as an oversight rather than a deliberate call.
- tasks.md: check off T021b/T021c — node_count["user"] is implemented and
  tested, the checklist just wasn't updated.
- data-model.md, contracts/telemetry-payload.md, research.md: drop TIMEDOUT
  from the webhook-failure states — it isn't a real Prefect StateType; the
  collector only counts FAILED/CRASHED. Already flagged as a deferred doc
  fix in opsmill-implement-report.md; finishing it now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the half-open→inclusive boundary conversion (window_end minus one
microsecond) into window.inclusive_end; the windowed event filter and the
webhook flow-run filter now share it, with the rationale documented once.
Extract the count-by POST boilerplate (post, raise, parse, list-guard) into a
single _post_count_by helper reused by the three count-by callers.

Review feedback:
- Derive the webhook flow name from the workflow catalogue (WEBHOOK_PROCESS.name)
  instead of hardcoding the string.
- Route safe_metric's degradation warning through the infrahub.tasks logger so
  it surfaces in Prefect task logs (a bare module logger does not).
- Remove .specify/feature.json (speckit artifact, being gitignored upstream).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two review findings on the telemetry PR were avoidable mistakes worth writing
down so they don't recur: a workflow name hardcoded instead of read from the
catalogue, and a helper logging through a module logger Prefect never surfaces.

Document both in the async-tasks knowledge doc (mechanism + why, naming the
code), with brief authoring pointers in the creating-async-tasks guide, and
nudge the backend router to load the knowledge base for relevant tasks. Align
the telemetry test's webhook flow name to WEBHOOK_PROCESS.name to match
production.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove the unused module-level logger and its import in tasks.py — every log
call lives inside the flow, which uses Prefect's run logger, so the module
logger was dead and would not surface in Prefect regardless.

Merge the small window module (window functions + WINDOW_LENGTH) into utils,
delete window.py, and update the importers and the knowledge-doc key-locations
table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The branch had removed this speckit runtime pointer; restore develop's version
so this PR carries no diff for it. Its removal/gitignore is handled separately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codspeed-hq

codspeed-hq Bot commented Jul 30, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 12 untouched benchmarks
🆕 1 new benchmark

Performance Changes

Benchmark BASE HEAD Efficiency
🆕 test_query_rel_one_id_only N/A 655.3 ms N/A

Comparing release-1.11 (3064a42) with develop (cb1c605)

Open in CodSpeed

@bilalabbad
bilalabbad requested a review from a team as a code owner July 30, 2026 08:02
@github-actions github-actions Bot added the group/frontend Issue related to the frontend (React) label Jul 30, 2026
…ver lookup (#10069)

The coalesced merge and rebase recompute already refreshes the stored cross-relationship
human-friendly id. The earlier reproduction read InfrahubNode.hfid, which the SDK computes on
the client side from a cached peer, so it looked stale while the server value was correct.

Assert the server value through get_one_by_hfid: after merge and rebase the reader is found by
its new id and no longer by the old one. Drop the xfail markers so the tests guard the behavior.
Replace the two builder-level component tests with one unit test that checks the builder
schedules the HFID recompute for a cross-relationship id.
@github-actions github-actions Bot added the group/backend Issue related to the backend (API Server, Git Agent) label Jul 30, 2026
petercrocker and others added 12 commits July 30, 2026 12:21
infrahub-demo-sp already has the receiving update-infrahub.yml and
update-infrahub-sdk.yml workflows, but it was never added to this matrix,
so they have never fired. Adding it means a new Infrahub release opens a
version-bump PR there, whose CI runs the demo's integration suite against
the release.
Deleting a node that other nodes read across a relationship left the readers with derived values (display label, human-friendly id, computed attribute) that still named the deleted node after a merge or rebase.

An update whose changed fields include a relationship now also recomputes the node's own derived values that read across it, keyed by the node's own id. This covers both merge and rebase through the shared coalesced deriver, and attribute-only updates are unchanged.

Relationship resolution also tolerates profile and template kinds, so such a node in the change set no longer aborts the whole coalesced recompute.
…mber pool (closes #7836) (#10085)

* test: add failing test for IFC-2095-jinja2-unallocated-pool

Reproduces the Jinja2 computed-attribute crash when a macro formats a
pool-sourced attribute that is not yet allocated during node creation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip Jinja2 macros referencing unallocated pool attributes

A computed Jinja2 attribute whose template reads a pool-sourced local
attribute is now left unrendered while that attribute has no allocated
value, instead of rendering against None. The macro is evaluated once
the pool allocation has taken place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover independent macros rendering when a pool is unallocated

Adds a Node.new(process_pools=False) case asserting that a macro which
does not reference the unallocated pool still renders, guarding against
skipping every macro instead of only pool-dependent ones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: add changelog fragment for jinja2 pool fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: reuse Snow schema helper for pool computed-attribute tests

Derives the number-pool + Jinja2 computed-attribute schema from the
shared Snow helper via deepcopy, overriding only the identifier template
to exercise the leading-zero format filter, instead of defining a
bespoke inline schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: guard recompute path against unallocated pool variables

_resolve_jinja2_variables can now return None for a pool-sourced
dependency that is not yet allocated; the recompute path skips that
attribute instead of passing None into template rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract pending-pool-dependency check from variable resolver

Keeps _resolve_jinja2_variables a pure variable-to-value mapping and
moves the "can this macro be rendered yet" decision into a dedicated
predicate, shared by the create and recompute paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover GraphQL create and mixed-variable pool macros

Adds a GraphQL create path exercising the reporter's scenario end to end,
and a macro referencing both the pool value and a plain attribute to
confirm every variable renders once the pool is allocated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: move GraphQL pool-macro test to the GraphQL mutation suite

Relocates the GraphQL create test next to the other jinja2-computed-
attribute mutation tests, and extracts the shared Snow schema builder and
number-pool provisioning into tests/helpers/number_pool so both the
core-layer and GraphQL-layer tests reuse them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: build a fresh ComputedAttribute in the number-pool helper

Assigns a new ComputedAttribute rather than mutating an optional field,
so the helper type-checks under ty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: key changelog fragment to GitHub issue 7836

Renames the orphan changelog fragment so towncrier renders the link to
the original issue this fix closes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: defer computed attributes chained on a skipped pool macro

When a computed attribute is skipped because it reads an unallocated pool
value, any computed attribute that references it is now deferred as well,
instead of rendering against the skipped value. Macros are already
iterated in dependency order, so tracking the skipped set is enough to
cascade the skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract referenced-root-fields helper for macro dependencies

Replaces the hand-rolled `variable.split("__")[0]` root extraction, which
was repeated in both the create and recompute macro paths, with a single
named helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: move referenced-root-fields onto InfrahubJinja2Template

The root-field extraction operates only on a template's variables, so it
belongs on the template rather than as a static method on Node. Both the
create and recompute macro paths call it through the template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-import-IFC-336

Fix Jinja2 comparison during repository imports
…10062)

* perf(graphql): skip peer hydration for id-only single relationships

When a cardinality-one relationship query requests only the peer node's
`id` (no properties, metadata, or additional node fields), return the
peer ID already loaded on the parent instead of hydrating a full peer
Node via NodeDataLoader. This avoids redundant database work on
relationship-heavy queries such as cable-plan reports.

The resolver falls through to the existing NodeDataLoader / query_peers
paths whenever any other field, property, or metadata is requested, so
behavior is unchanged for all other queries.

* fix(graphql): skip id-only relationship shortcut for generic peers

The id-only single-relationship shortcut returns {"id": peer_id} without
the peer kind. For a relationship whose peer is a generic, the GraphQL
node field is an interface whose resolve_type needs the kind, so it fails
with "Unable to identify the type of the instance." Restrict the shortcut
to concrete peers; generic peers fall back to full hydration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZdYyE4JewWbMZAbvWPjQe

* perf(graphql): carry peer kind so generic id-only relationships skip hydration

The id-only single-relationship shortcut had to be disabled for generic
peers: it returned {"id": peer_id} without a kind, and a generic peer
resolves to a GraphQL interface whose resolve_type indexes the type
registry by kind. That excluded a large share of core-schema
relationships from the optimization.

The peer's concrete kind was available all along. The relationship query
already binds the peer vertex and returns peer.uuid, so returning
peer.kind alongside it costs no extra round trip. Thread that kind
through GroupedPeerNodes, PeerWithRelationshipMetadata and Relationship
so the preloaded stub on a node's GraphQL response can carry __kind__,
and let the shortcut serve generic peers from it.

The shortcut declines whenever the kind is absent and the resolver
hydrates as before, so correctness never depends on the enrichment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(graphql): assert generic-peer id-only relationship skips hydration

Add a component test that exercises the id-only single-relationship shortcut
against a cardinality-one relationship whose peer is a generic. It monkeypatches
NodeDataLoader.load to raise, so a regression to the correct-but-slower
hydrating path fails loudly instead of passing silently.

* test(benchmark): add id-only single-relationship benchmark

Add test_query_rel_one_id_only mirroring test_query_rel_one but selecting
only the peer id (repository { node { id } }), so the id-only
single-relationship shortcut is exercised and validated by CodSpeed CI.

* update name, reduce comment

* consolidate tests

* reduce size of huge test file

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>
* refactor(validators): inject the constraint determiner and merger into MergeConstraintValidator

MergeConstraintValidator built its determiner and constraint-info merger inside
validate() because both needed the candidate schema, which is only known per
call. Turn the schema into an argument on their entry methods so the components
can be constructed at the wiring layer and injected.

- ConstraintValidatorDeterminer.get_constraints() takes schema_branch
- UniquenessConstraintScoper.requires_validation()/affected_node_uuids() take schema_branch
- UniquenessConstraintDeduplicator.deduplicate() takes schema_branch
- ConstraintInfoMerger.merge() takes schema_branch
- MergeConstraintValidator receives determiner + merger, no longer needs db

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix test to run assertions

* one integration test for node-scoped uniqueness violations

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…9586)

* docs: polish 1.9.0 release notes — voice, clarity, learn-more links

Apply a voice and clarity pass to the 1.9.0 release notes:

- Voice: drop the marketing opener, remove a forbidden word and an
  idiom, replace product-as-agent value claims, cut vendor-positioning
  phrasing.
- Clarity for an international audience: split over-packed sentences,
  expand SIEM and hfid on first use, replace residual colloquialisms.
- Educational: add a "why" to namespace restrictions; add six
  "Learn more" links from feature sections to their docs pages.
- Fixes: correct the "are can be forwarded" grammar error and resolve
  the infrahub-sdk version placeholder to 1.20.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: polish 1.8.0 release notes — voice, clarity, learn-more links

Apply the same voice and clarity pass to the 1.8.0 notes:

- Voice: drop the marketing opener and filler ("now simpler",
  "continues to evolve", "enhance the day-to-day experience"), fix a
  first-person "we can now".
- Clarity: fix the File Object terminology drift and a comma splice,
  add four "Learn more" links to the feature docs.
- Correctness: fix the duplicate "Second" migration step (-> Third),
  two grammar errors ("helps speeding up", "command need to run"),
  and a stray semicolon in the MIME-type list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: replace figurative "carry/carries" in 1.9.0 notes

"carries the event as JSON" -> "contains"; "Webhooks can now carry ...
headers" -> "send". Direct verbs per the voice rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Damien Garros <damien@opsmill.com>
Supersedes #10078, which cannot be resolved in place because its head is
`stable` (conflict resolution would require committing to `stable`).

Conflicts resolved:

- frontend/app/src/shared/components/inputs/relationship-many.tsx
  Import conflict only. `release-1.11` moved the node types out of
  `@/entities/nodes/types` into `@/entities/nodes/object/domain/model/node`
  (architecture refactor #9792); `stable` added `NodeFieldsWithMetadata` to
  the old path. Kept `release-1.11`'s module path and `stable`'s added symbol.

- frontend/app/.betterer.results
  Generated file; both sides only differed in content hashes and line
  numbers for the same three known tsc errors. Regenerated on the merged
  tree rather than hand-picking a side.

Silent semantic conflicts git merged cleanly but which do not compile
(both are the same deleted-module problem as above, in files only `stable`
touched, so git had no conflict to report):

- useCommonParentFilter.ts, relationship-one.tsx,
  relationship-hierarchical-input.tsx, add-relationship-action.tsx
  repointed `@/entities/nodes/types` -> `@/entities/nodes/object/domain/model/node`
- useCommonParentFilter.ts repointed `@/entities/schema/types`
  -> `@/entities/schema/domain/model/schema`

No behaviour was changed on either side; every hunk from both branches is
preserved.

Verified on the merged tree: biome ci, knip, betterer ci, vitest
(164 files / 1108 tests), ruff check, ruff format --check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The count-by-kind query matches on the vertex kind property, which only
ever holds a node's concrete kind; a generic passed as a plain string
would silently count zero. Accept list[NodeSchema] instead of list[str]
so handing it a GenericSchema is a type error caught by mypy/ty, and
document the property-vs-labels constraint in the docstring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(frontend): filter relationship selectors by common_parent (#10039)

Relationship selectors in object forms now honor the `common_parent` schema
property: options are filtered to peers that share the same parent as the value
picked for the referenced relationship in the same form, instead of listing
every peer.

- Add useCommonParentFilter hook: watches the sibling common_parent field and
  derives a single-hop `<X>__ids` filter (plus a matching RelationshipInput
  parent shape).
- Apply across the many, node, generic, and hierarchical relationship fields.
- Hide the manual parent picker on cardinality-one fields when common_parent is
  set, since the parent is then driven by the sibling field.

Keep the selection consistent with the filter so it can't be bypassed:
- Clear the current selection when the chosen parent changes (a peer valid under
  the old parent no longer satisfies the constraint).
- Pre-fill the inline "Add new" create form with the chosen parent, so a peer
  created there satisfies the constraint instead of being an escape hatch.
- Keep the filter applied on UUID searches (opt-in), and drop the hierarchical
  "Explore" tree tab, which browses a different axis and can't honor the filter.

Fixes IFC-1646.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip merged branches during git repository sync (#9938)

fix: skip merged branches during git repository sync

A git branch mapping to a merged (read-only) Infrahub branch caused
collect_pending_imports to issue a CoreRepositoryUpdate, which the graph
rejects for merged branches. The unhandled error aborted the entire sync
flow on every cron cycle, so no branches or repositories synced at all.

Branches in a terminal status are now skipped during collection, letting
the remaining branches and repositories sync as normal.

Also:
- Add a regression test covering the merged-branch case.
- Stub sdk.branch.all() in the git conftest, shared by the sync tests and
  the lock-scope test. The skip introduces a branch.all() call on the
  sync path, which the dummy SDK requester answers with an empty payload
  and raises KeyError: 'Branch'.
- Add a changelog fragment.

Fixes #9931

* docs: add local development and evaluation sizing to hardware requirements (#10071)

* docs: add local development and evaluation sizing to hardware requirements

* docs: address review — recommend 6/8 cores for local eval, drop changelog

* docs: document Community single-core Neo4j limitation (#10072)

* docs: document Community single-core Neo4j limitation

* docs: address review — clarify Neo4j Community single-core, drop changelog

* docs: link hardware requirements from Community install page (#10073)

* docs: link hardware requirements from Community install page

* docs: drop changelog for minor doc link

* ci: dispatch Infrahub releases to infrahub-demo-sp (#10076)

infrahub-demo-sp already has the receiving update-infrahub.yml and
update-infrahub-sdk.yml workflows, but it was never added to this matrix,
so they have never fired. Adding it means a new Infrahub release opens a
version-bump PR there, whose CI runs the demo's integration suite against
the release.

* fix: render Jinja2 computed attributes sourced from an unallocated number pool (closes #7836) (#10085)

* test: add failing test for IFC-2095-jinja2-unallocated-pool

Reproduces the Jinja2 computed-attribute crash when a macro formats a
pool-sourced attribute that is not yet allocated during node creation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: skip Jinja2 macros referencing unallocated pool attributes

A computed Jinja2 attribute whose template reads a pool-sourced local
attribute is now left unrendered while that attribute has no allocated
value, instead of rendering against None. The macro is evaluated once
the pool allocation has taken place.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover independent macros rendering when a pool is unallocated

Adds a Node.new(process_pools=False) case asserting that a macro which
does not reference the unallocated pool still renders, guarding against
skipping every macro instead of only pool-dependent ones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: add changelog fragment for jinja2 pool fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: reuse Snow schema helper for pool computed-attribute tests

Derives the number-pool + Jinja2 computed-attribute schema from the
shared Snow helper via deepcopy, overriding only the identifier template
to exercise the leading-zero format filter, instead of defining a
bespoke inline schema.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: guard recompute path against unallocated pool variables

_resolve_jinja2_variables can now return None for a pool-sourced
dependency that is not yet allocated; the recompute path skips that
attribute instead of passing None into template rendering.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract pending-pool-dependency check from variable resolver

Keeps _resolve_jinja2_variables a pure variable-to-value mapping and
moves the "can this macro be rendered yet" decision into a dedicated
predicate, shared by the create and recompute paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: cover GraphQL create and mixed-variable pool macros

Adds a GraphQL create path exercising the reporter's scenario end to end,
and a macro referencing both the pool value and a plain attribute to
confirm every variable renders once the pool is allocated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: move GraphQL pool-macro test to the GraphQL mutation suite

Relocates the GraphQL create test next to the other jinja2-computed-
attribute mutation tests, and extracts the shared Snow schema builder and
number-pool provisioning into tests/helpers/number_pool so both the
core-layer and GraphQL-layer tests reuse them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: build a fresh ComputedAttribute in the number-pool helper

Assigns a new ComputedAttribute rather than mutating an optional field,
so the helper type-checks under ty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: key changelog fragment to GitHub issue 7836

Renames the orphan changelog fragment so towncrier renders the link to
the original issue this fix closes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: defer computed attributes chained on a skipped pool macro

When a computed attribute is skipped because it reads an unallocated pool
value, any computed attribute that references it is now deferred as well,
instead of rendering against the skipped value. Macros are already
iterated in dependency order, so tracking the skipped set is enough to
cascade the skip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: extract referenced-root-fields helper for macro dependencies

Replaces the hand-rolled `variable.split("__")[0]` root extraction, which
was repeated in both the create and recompute macro paths, with a single
named helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor: move referenced-root-fields onto InfrahubJinja2Template

The root-field extraction operates only on a template's variables, so it
belongs on the template rather than as a static method on Node. Both the
create and recompute macro paths call it through the template.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* perf(graphql): skip peer hydration for id-only single relationships (#10062)

* perf(graphql): skip peer hydration for id-only single relationships

When a cardinality-one relationship query requests only the peer node's
`id` (no properties, metadata, or additional node fields), return the
peer ID already loaded on the parent instead of hydrating a full peer
Node via NodeDataLoader. This avoids redundant database work on
relationship-heavy queries such as cable-plan reports.

The resolver falls through to the existing NodeDataLoader / query_peers
paths whenever any other field, property, or metadata is requested, so
behavior is unchanged for all other queries.

* fix(graphql): skip id-only relationship shortcut for generic peers

The id-only single-relationship shortcut returns {"id": peer_id} without
the peer kind. For a relationship whose peer is a generic, the GraphQL
node field is an interface whose resolve_type needs the kind, so it fails
with "Unable to identify the type of the instance." Restrict the shortcut
to concrete peers; generic peers fall back to full hydration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZdYyE4JewWbMZAbvWPjQe

* perf(graphql): carry peer kind so generic id-only relationships skip hydration

The id-only single-relationship shortcut had to be disabled for generic
peers: it returned {"id": peer_id} without a kind, and a generic peer
resolves to a GraphQL interface whose resolve_type indexes the type
registry by kind. That excluded a large share of core-schema
relationships from the optimization.

The peer's concrete kind was available all along. The relationship query
already binds the peer vertex and returns peer.uuid, so returning
peer.kind alongside it costs no extra round trip. Thread that kind
through GroupedPeerNodes, PeerWithRelationshipMetadata and Relationship
so the preloaded stub on a node's GraphQL response can carry __kind__,
and let the shortcut serve generic peers from it.

The shortcut declines whenever the kind is absent and the resolver
hydrates as before, so correctness never depends on the enrichment.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(graphql): assert generic-peer id-only relationship skips hydration

Add a component test that exercises the id-only single-relationship shortcut
against a cardinality-one relationship whose peer is a generic. It monkeypatches
NodeDataLoader.load to raise, so a regression to the correct-but-slower
hydrating path fails loudly instead of passing silently.

* test(benchmark): add id-only single-relationship benchmark

Add test_query_rel_one_id_only mirroring test_query_rel_one but selecting
only the peer id (repository { node { id } }), so the id-only
single-relationship shortcut is exercised and validated by CodSpeed CI.

* update name, reduce comment

* consolidate tests

* reduce size of huge test file

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>

* docs: polish 1.8.0 and 1.9.0 release notes (voice, clarity, links) (#9586)

* docs: polish 1.9.0 release notes — voice, clarity, learn-more links

Apply a voice and clarity pass to the 1.9.0 release notes:

- Voice: drop the marketing opener, remove a forbidden word and an
  idiom, replace product-as-agent value claims, cut vendor-positioning
  phrasing.
- Clarity for an international audience: split over-packed sentences,
  expand SIEM and hfid on first use, replace residual colloquialisms.
- Educational: add a "why" to namespace restrictions; add six
  "Learn more" links from feature sections to their docs pages.
- Fixes: correct the "are can be forwarded" grammar error and resolve
  the infrahub-sdk version placeholder to 1.20.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: polish 1.8.0 release notes — voice, clarity, learn-more links

Apply the same voice and clarity pass to the 1.8.0 notes:

- Voice: drop the marketing opener and filler ("now simpler",
  "continues to evolve", "enhance the day-to-day experience"), fix a
  first-person "we can now".
- Clarity: fix the File Object terminology drift and a comma splice,
  add four "Learn more" links to the feature docs.
- Correctness: fix the duplicate "Second" migration step (-> Third),
  two grammar errors ("helps speeding up", "command need to run"),
  and a stray semicolon in the MIME-type list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs: replace figurative "carry/carries" in 1.9.0 notes

"carries the event as JSON" -> "contains"; "Webhooks can now carry ...
headers" -> "send". Direct verbs per the voice rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Damien Garros <damien@opsmill.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Alex Gittings <agitting96@gmail.com>
Co-authored-by: iddocohen <iddocohen@gmail.com>
Co-authored-by: Pete Crocker <pete@petecrocker.com>
Co-authored-by: Pol Michel <40861490+polmichel@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Aaron McCarty <aaron@opsmill.com>
Co-authored-by: Yvonne <yvonne@bluecanyon.us>
Co-authored-by: Yvonne <yvonne@opsmill.com>
Co-authored-by: Damien Garros <damien@opsmill.com>
@pa-lem
pa-lem requested a review from a team as a code owner July 31, 2026 10:46
@github-actions github-actions Bot added type/documentation Improvements or additions to documentation group/ci Issue related to the CI pipeline labels Jul 31, 2026
ajtmccarty and others added 2 commits July 31, 2026 07:15
* refactor(core): make _normalize_value a classmethod

Allow a value to be checked for canonicality without building an attribute
instance. No override used instance state, so behavior is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(core): add the IPAddress attribute kind

Store a bare IP address, rejecting any value that carries a prefix length or
netmask, and normalize IPv6 to its compressed lowercase form.

Reuse the AttributeIPHost value vertex and its binary index by returning
AttributeDBNodeType.IPHOST, so no graph schema change, index or migration is
needed. prefixlen is written as the family maximum because a bare address is a
single host and neo4j refuses to MERGE on a null property; it is deliberately
absent from the GraphQL type and from get_allowed_property_in_path.

Values sort lexically rather than numerically, since the shared binary index is
only reachable through IPAM's own queries.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(schema): reject non-canonical values when changing an attribute kind

A kind change does not rewrite stored values, so switching an attribute to
IPHost left a bare 10.0.0.1 in the database where the canonical form is
10.0.0.1/32, making value filters and uniqueness comparisons match a stale
string. Flag any stored value that is not already canonical for the new kind.

The check needs no list of the kinds it applies to: kinds that do not normalize
inherit an identity _normalize_value, so it is a no-op for them and covers a
future normalizing kind for free. In practice it applies to IPHost, IPNetwork,
IPAddress and MacAddress.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(generated): regenerate schema, docs and frontend types for IPAddress

Output of backend.generate, schema.generate-graphqlschema,
schema.generate-jsonschema, docs.generate and the frontend codegen.

The graphql-cache.d.ts churn is gql.tada rehashing every cached document
because the schema changed; none of it is specific to the new kind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(frontend): support the IPAddress attribute kind

Register the kind so it renders as a plain text input in object forms, shows as
a column in list views, and offers a text filter. The four switches it is added
to fall through to warnUnexpectedType and render nothing for an unknown kind, so
each case is what keeps the field from silently disappearing.

Validate the value in the form as well, since a prefixed address is a mistake
worth catching before the round trip: a value containing a slash is reported as
needing a bare address, and anything else malformed as an invalid IPv4 or IPv6
address. Leading zeros are rejected to match the backend.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: document the IPAddress attribute kind

Add the kind to the hand-written kind list and the UI-behaviour table, and note
on the IPHost entry that it stores a prefix so the two read as distinct choices.

Record in the knowledge doc that _normalize_value is a classmethod so a value
can be checked without an attribute instance, and that a kind change is only
allowed when the stored values are already canonical for the new kind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(sdk): bump python_sdk for the IPAddress attribute kind

Advances python_sdk to the latest infrahub-develop and adds the generated
IPAddress attribute-kind models, which unblocks the SDK node tests for a bare
address.

The pointer spans 14 upstream commits as well as the IPAddress change, mostly
the infrahubctl schema-format work, so an unrelated SDK regression bisected to
this commit most likely comes from those.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(frontend): count IPv6 groups correctly in the IPAddress validator

A trailing dotted quad carries 32 bits, so it stands for the final two groups
rather than one. Counting it as one rejected valid addresses such as
1:2:3:4:5:6:1.2.3.4. Allowing eight explicit groups alongside a "::" run also
accepted invalid ones such as ::1:2:3:4:5:6:7:8, since the run has to stand for
at least one group of zeros.

The accept and reject cases are checked against ipaddress.ip_address so the form
validation and the backend agree on the same inputs.

Also refresh the betterer results: adding IPAddress to ATTRIBUTE_KIND changed the
content hashes of the two switch files and the text of several recorded errors
that embed the AttributeKind union, which the CI-mode check treats as a change
even though the error count is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* add "netmask" to spelling exceptions

* bump python sdk to latest infrahub-develop after SDK PR merged

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
IFC-2950 (#10102)

Add three known limitations of the merge follow-up regeneration to the
performance-scenarios spec, each carrying its tracking ticket and the
release-1.11 code reference:

- relationship-reached data widens selection to the whole target group
  (IFC-2946)
- no size ceiling on the serialized merge diff summary versus the cache
  backend per-value limit (IFC-2943)
- each selective-regen merge and rebase leaks an orphaned persisted diff
  root (IFC-2941)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the type/spec A specification for an upcoming change to the project label Jul 31, 2026
bilalabbad and others added 4 commits July 31, 2026 21:51
…ly (#10095)

* feat(schema): report the schema fields the load endpoint does not apply

Loading a schema dropped every field the user may not set without saying so, so
a misspelled key produced a schema quietly different from the one the author
wrote. Classify them instead: a name the contract knows at that location but
the user may not set is reported as a warning and still dropped, keeping the
read-back, edit, re-load round trip working; any other name is rejected.

The generator gains a table of the non-settable fields of each write class,
emitted into the SDK as schema/generated/contract.py. It is derived from two
diffs: the read variant of a class against its write variant, and the internal
pydantic counterpart of a value model against its generated write model. The
second diff covers the parameters, choice, computed-attribute and extension
models, which are declared in the generator rather than derived from
internal.py and so omit the id/state bookkeeping every internal schema model
carries; those names appear in any schema dumped from the internal models.

SchemaLoadAPI validates through a wrap validator so the warnings, visible only
on the raw payload, can be carried on the instance and merged into the response
alongside gather_warnings(). They ride the existing deprecation warning type,
which an SDK older than this change can still parse. Repository imports report
them too, and fail on an unknown field.

Two shapes that previously loaded now fail: a misspelled field name, and
attribute parameters belonging to a different attribute kind, which configured
nothing on the kind they were set on.

The published request schema is unchanged -- the load endpoint still validates
through InfrahubSchemaWrite alone, so no read-only field is advertised as
settable and schema/openapi.json is byte-identical.

Also return the collected warnings when the submitted schema matches the one
already loaded; the early return dropped them, so a warning went unreported on
every load after the first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: drop possessive "SDK's" flagged by the release-notes vale gate

The validate-release-notes-style job runs vale over ./changelog, where
Infrahub.spelling rejects the possessive. Use the attributive form the
existing fragments already use.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: name nested read-only fields relative to their owner

backend-tests-integration failed on test_check_schema_02, which submits a full
internal dump and asserted the check returned no warnings. The submitted dump
legitimately carries the fields Infrahub owns, so the assertion had to change --
but the warnings it exposed showed a defect: a nested finding carried the bare
key, so `parameters.id` was reported as `id` against the owning attribute, where
`id` is in fact settable, and collided with the `id` from another block once
grouped by name.

Bump python_sdk to qualify the name with the fields walked since the last kind
or element, and assert the resulting warnings in the integration test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: parametrize the read-only table check with a dataclass

The case data was held in a dict keyed by family name, parametrized over the
keys and looked up inside the test -- a mix of the two styles. Use the dataclass
pattern the testing rules call for, keeping the pytest ids unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs: describe the write contract against the last released version

The write-contract work is not released yet, so its changelog and deprecation
guide were describing a change history relative to an unreleased intermediate
state rather than to v1.10.6. Two of the resulting claims were wrong: unknown
fields and a missing `version` were already rejected there, since the load
endpoint validated through a model with `extra="forbid"`.

Fold this branch's fragment and the intermediate read-only fragment into the one
pending `changed` fragment, so 1.11 publishes a single accurate story, and
restate the guide's "what changed" against v1.10.6: constrained values and
misplaced attribute `parameters` are the new rejections, read-only fields are
newly reported as warnings, and an unrecognized field is rejected as before with
only its wording changed.

The unchanged-schema warnings fragment stays: that early return drops warnings
in v1.10.6, so it is a genuine fix against released behaviour.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(schema): resolve the read-only table in the generator

The generated table held each class's own read-only fields, leaving consumers to
union them across the model's MRO. Resolve the parent chain here so each entry is
complete and a lookup needs only the class name, and bump python_sdk for the
matching consumer change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test: assert the read-only table resolves every inherited field

The offline validator looks a class up by name alone, so a generator that
emitted only a class's own read-only fields would let an inherited one fall
through as an unknown field, turning a value that must be tolerated on a round
trip into a hard error. Nothing guarded that, since the tables asserted per
family only cover the five classes paired with a read model.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(sdk): point python_sdk at merged infrahub-develop

The companion SDK pull request is merged, so the submodule tracks the merge
commit on infrahub-develop instead of the feature branch. The tree is unchanged:
the merge carries no work beyond what the pointer already referenced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(backend): (INFP-589) Collect more metrics and introduce 24h windowing in telemetry collection
…10096)

* fix(fingerprint): trust dependencies_complete for Jinja2 transforms

Make the commit-id fold gate builder-aware instead of uniform. A Jinja2
transform with a complete dependency closure now produces a stable
fingerprint without an explicit watch declaration, so unrelated commits no
longer churn its fingerprint.

Jinja2 completeness is sound: it comes from a real transitive parse of the
template include/import/extends graph, so a complete closure alone is
enough. A dynamic or unresolvable reference still drops completeness to
False and keeps the commit id folded. Python transforms and generators are
unchanged - their completeness flag is only the package-directory floor, so
a present watch remains required to omit the commit id.

Amends spec FR-016/FR-019 with a builder-aware note.

Ref: IFC-2952
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/backend Issue related to the backend (API Server, Git Agent) group/ci Issue related to the CI pipeline group/frontend Issue related to the frontend (React) type/documentation Improvements or additions to documentation type/spec A specification for an upcoming change to the project

Projects

None yet

Development

Successfully merging this pull request may close these issues.